package cn.lsg.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;

/**
 * FTP 工具类
 * 
 */
public class UtilFtp {
	private final static Logger log = Logger.getLogger(UtilFtp.class);

	private static final FTPClient ftpClient = new FTPClient();

	private static String host, userName, password;
	private static int port = 21;
	private static int uploadTime = 0;

	// 临时目录
	private static String tmpDir = UtilFtp.class.getResource("/").getPath();

	static {// 配置文件
		Properties prop = null;
		File file = new File(UtilFtp.class.getResource("/").getPath()
				+ "WebConfig.properties");
		if (file.isFile()) {
			try {
				prop = new Properties();
				prop.load(new FileInputStream(file));
			} catch (IOException e) {
				e.printStackTrace();
			}
			host = prop.getProperty("FTP_Server");
			userName = prop.getProperty("FTP_UserName");
			password = prop.getProperty("FTP_password");
			port = by.parseInt(prop.getProperty("FTP_Port"));
		} else {
			log.warn("FTP配置文件找不到：" + file.getPath());
		}
	}

	/**
	 * 上传文件
	 * 
	 * @param ftpDir
	 *            FTP目录
	 * @param filename
	 *            文件名称
	 * @param file
	 *            上传文件
	 * @throws Exception
	 */
	public synchronized static void uploadFile(String ftpDir, String filename,
			File file) throws Exception {
		try {
			uploadFile(ftpDir, filename, new FileInputStream(file));
		} catch (Exception e) {
			throw new Exception("FTP文件上传出错:" + e.getMessage(), e);
		}
	}

	/**
	 * 上传文件
	 * 
	 * @param uploadDir
	 * @param uploadFilename
	 * @param is
	 * @return
	 * @throws IOException
	 */
	public synchronized static void uploadFile(String uploadDir,
			String uploadFilename, InputStream is) throws Exception {
		try {
			uploadFileAgein(uploadDir, uploadFilename, is);
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				try {
					is.close();
				} catch (IOException e1) {
				}
			}
		}
	}

	/**
	 * 移除目录
	 * 
	 * @param ftpDir
	 *            FTP目录
	 * @throws Exception
	 */
	public synchronized static void removeDir(String ftpDir) throws Exception {
		try {
			String[] ns = getFtpClient().listNames(ftpDir);
			if (ns != null) {
				for (String s : ns) {
					getFtpClient().deleteFile(ftpDir + "/" + s);
				}
			}
			boolean b = getFtpClient().deleteFile(ftpDir);
			b = getFtpClient().removeDirectory(ftpDir);
			if (!b) {
				throw new Exception("文件删除失败：" + ftpDir);
			}
		} catch (Exception e) {
			throw new Exception("文件删除异常：" + e.getMessage(), e);
		}
	}

	/**
	 * 读取文件
	 * 
	 * @param remoteUri
	 * @return
	 * @throws IOException
	 */
	public synchronized static InputStream readFile(String remoteUri)
			throws Exception {
		InputStream is = null;
		ByteArrayOutputStream bos;
		try {
			is = getFtpClient().retrieveFileStream(remoteUri);

			bos = new ByteArrayOutputStream();
			byte[] bit = new byte[1024];
			int len = 0;

			while ((len = is.read(bit)) != -1) {
				bos.write(bit, 0, len);
			}
			getFtpClient().completePendingCommand();
		} catch (Exception e) {
			throw e;
		} finally {
			if (is != null) {
				is.close();
			}
		}
		return (new ByteArrayInputStream(bos.toByteArray()));

	}

	public synchronized static File localFtpFile(String remoteUri)
			throws Exception {
		String tmp = tmpDir + "/";
		File file = new File(tmp);
		if (!file.isDirectory()) {
			file.mkdirs();
		}

		String fileName = by.getUUID() + "." + UtilHttp.getExt(remoteUri);

		file = new File(tmp + fileName);
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(readFile(remoteUri));
			bos = new BufferedOutputStream(new FileOutputStream(file));

			int len;
			byte[] bit = new byte[1024];
			while ((len = bis.read(bit)) != -1) {
				bos.write(bit, 0, len);
			}
		} catch (Exception e) {
			log.error("【严重】程序异常", e);
			throw new Exception("FTP文件本地化异常:" + e.getMessage());
		} finally {
			if (bos != null) {
				bos.flush();
				bos.close();
			}
			if (bis != null) {
				bis.close();
			}
		}
		return file;
	}

	/**
	 * 创建文件夹
	 * */
	public synchronized static boolean makeDirs(String dir) {
		String[] folders = dir.split("/");
		String str = "";
		boolean flag = true;
		for (String folder : folders) {
			str += folder + "/";
			try {
				if (!checkDir(str)) {
					getFtpClient().makeDirectory(str);
				}
			} catch (Exception e) {
				flag = false;
			}
		}
		return flag;
	}

	/**
	 * 文件复制
	 * 
	 * @param remoteUri
	 * @param copyToDir
	 * @param copyToFileName
	 * @throws IOException
	 */
	public synchronized static void copy(String remoteUri, String copyToDir,
			String copyToFileName) throws Exception {
		InputStream is = readFile(remoteUri);

		uploadFile(copyToDir, copyToFileName, is);
	}

	/**
	 * 连接 FTP 服务器
	 * 
	 * @return
	 * @throws IOException
	 */
	private synchronized static FTPClient connection() throws IOException {

		ftpClient.connect(UtilFtp.host, UtilFtp.port);
		ftpClient.login(UtilFtp.userName, UtilFtp.password);
		// 看返回的值是不是230，如果是，表示登陆成功
		int reply = ftpClient.getReplyCode();
		// 以2开头的返回值就会为真
		if (!FTPReply.isPositiveCompletion(reply)) {
			ftpClient.disconnect();
			return null;
		}
		ftpClient.setBufferSize(1024);
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

		return ftpClient;
	}

	/**
	 * 上传文件
	 * 
	 * @param ftpDir
	 * @param fileName
	 * @param is
	 * @throws IOException
	 */
	private synchronized static void uploadFileAgein(String ftpDir,
			String fileName, InputStream is) throws Exception {
		try {
			FTPClient _ftp = getFtpClient();
			_ftp.enterLocalPassiveMode();
			if (!checkDir(ftpDir)) {
				boolean b = makeDirs(ftpDir);
				if (!b) {
					throw new Exception("FTP上传文件夹创建错误！");
				}
			}
			_ftp.changeWorkingDirectory(ftpDir);
			_ftp.storeFile(fileName, is);
		} catch (Exception e) {
			uploadTime++;
			if (uploadTime < 3) {
				uploadFileAgein(ftpDir, fileName, is);
			} else {
				uploadTime = 0;
				throw e;
			}
		}
	}

	/**
	 * 检查目录是否存在
	 * 
	 * @param dir
	 * @return
	 * @throws IOException
	 */
	private synchronized static boolean checkDir(String dir) throws Exception {
		return getFtpClient().changeWorkingDirectory(dir);
	}

	private synchronized static FTPClient getFtpClient() throws Exception {
		boolean b = true;
		try {
			b = ftpClient.sendNoOp();
		} catch (IOException e1) {
			b = false;
		}
		int i = 0;
		while (b == false) {
			if (i >= 4) {
				throw new Exception("FTP无法连接");
			}
			i++;
			try {
				connection();
				b = ftpClient.sendNoOp();
			} catch (IOException e) {
				b = false;
			}
		}
		return ftpClient;
	}

}
